Skip to content

Fix duplicated prefix and captured sibling when replacing a dotted key with a table#526

Open
Labib-Bin-Salam wants to merge 1 commit into
python-poetry:masterfrom
Labib-Bin-Salam:fix-replace-dotted-key-with-table
Open

Fix duplicated prefix and captured sibling when replacing a dotted key with a table#526
Labib-Bin-Salam wants to merge 1 commit into
python-poetry:masterfrom
Labib-Bin-Salam:fix-replace-dotted-key-with-table

Conversation

@Labib-Bin-Salam

Copy link
Copy Markdown

Summary

Replacing a dotted key's value with a table corrupted the output in two ways, reported in #524 and #513.

#524 — duplicated prefix on a spurious header:

doc = tomlkit.loads("fruit.apple = true\n")
doc["fruit"] = {"a": 1}
print(tomlkit.dumps(doc))

master:

[fruit]
fruit.a = 1

#513 — a following sibling is silently swallowed (the data changes):

doc = tomlkit.loads("a.b = 1\nc.d = 2\n")
doc["a"] = {}
print(tomlkit.dumps(doc))

master:

[a]

c.d = 2

c.d is now a child of [a].

Cause

A dotted key (a.b = 1 stores key a with is_dotted() == True) is only consistent with a super table, which renders inline. When the value is replaced by a plain dict, Container._replace_at inherits the old dotted key, but the new table is not a super table, so it renders with its own [header] while the dotted key still prefixes the children — and the header then captures every following entry that renders inline.

Fix

In _replace_at, when a non-super table replaces a dotted key:

  • drop the dotted key so the replacement renders as a plain table (fixes the duplicated prefix), and
  • if an inline sibling still follows, move the new table past it — reusing the existing value→table repositioning. That scan now treats dotted-key tables as inline (skipping them when locating the first real [header]), which additionally fixes the same capture for a plain value replaced by a table that sits before a dotted key.

Result:

# #524
[fruit]
a = 1

# #513
c.d = 2

[a]

Tests

Added four regression tests in tests/test_toml_document.py (both issue repros, a non-empty variant, and the value→table-before-dotted case). The full suite passes (1027, including the toml-test conformance suite); ruff and ruff format are clean.

Fixes #513
Fixes #524

…y with a table

Replacing a dotted key's value with a table (e.g. ``doc["a"] = {...}`` where
``a`` was parsed from ``a.b = ...``) kept the dotted key, which both duplicated
the prefix onto the new ``[a]`` header (python-poetry#524) and let the header swallow any
sibling that follows it on round-trip (python-poetry#513).

A dotted key only renders correctly alongside a super table; when the
replacement is a non-super table it now drops the dotted key, and when an
inline sibling still follows it moves past it -- mirroring the existing
value-to-table handling. That scan now skips dotted-key tables when looking
for the first real header, which additionally fixes the same capture for a
plain value replaced by a table before a dotted key.

Fixes python-poetry#513
Fixes python-poetry#524
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Assigning a dict over a dotted key renders a stale parent. prefix an emptied dotted-key captures the elements that follow it

1 participant